#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>
#include <malloc.h>
#include <sstream>
#include "Debug.h"
#include "define.h"
#include "HttpConn.h"
#include "NantSock.h"

using namespace netproxy;
using namespace std;

bool HttpConn::Connect( )
{
        m_lCurtime = time(NULL);
	if(m_socket == 0)
	{
		struct hostent *he;
		struct sockaddr_in their_addr;
		he = gethostbyname(m_sHostname.c_str());
		if((m_socket = socket(AF_INET,SOCK_STREAM,0))==-1)
		{
			perror("socketi error!");
                        m_bLive = false;
                        m_socket = 0;
			return false;
		}
                if(he == NULL)
                {
                       cerr<<"gethostbyname return NULL "<<endl;
                       return false;
                }

               
		their_addr.sin_family = AF_INET;
		their_addr.sin_port = htons( m_iPort );
		their_addr.sin_addr = *((struct in_addr *)he->h_addr);
		bzero(&(their_addr.sin_zero), 8);
		if(connect(m_socket, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) ==-1){
			perror("connect error!");
			close(m_socket);
			m_socket = 0;
			m_bLive = false;
			return false;
		}
/**
设置超时是因为，可能由于对方的原因导致此socket处于阻塞状态，从而使得整个netproxy处于阻塞状态！
*/

		struct timeval timeout = {0, 5000};
		setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout,  sizeof(struct timeval));
		setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout,  sizeof(struct timeval));
		int flags = 1;
		setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
		setsockopt( m_socket, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
		struct linger ling = {0, 0};
		setsockopt( m_socket, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
		setsockopt( m_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));

                m_iCounts = 0;
	}  
	m_bLive = true;
	return m_bLive;
}

bool HttpConn:: ReConnect()
{
	if(m_socket != 0)
	{
                close(m_socket);
		m_socket  = 0;
	}
	return Connect();
}

void HttpConn:: disConnect()
{
	if(m_socket != 0)
	{
		cout<<" close "<< m_sHostname.c_str()<<":"<<m_iPort <<endl;
                close(m_socket);
		m_socket  = 0;
		m_lLasttime = time(NULL);
		m_bLive = false;
	}
	else
		m_bLive = false;
}

int HttpConn:: Proxy(const char *data, unsigned dlen, char **wbuf, unsigned &wsize, unsigned &wbytes, bool bReply)
{ //   type(char:get=g, post=p) + request_len + request_string + post_length + post_data

	if(m_socket <= 0 )
		return -1;

	unsigned uint_len = sizeof(unsigned);
	if(dlen < 2+uint_len)
             return -1;
        char req_type = *data;
        if(req_type != 'g' && req_type != 'p')
            return -2;
        int req_len = 0;
        bcopy(data+1, &req_len, uint_len);
        unsigned used = uint_len + 1;
        if(used + req_len > dlen)        
             return -1;
        char request[req_len + 1];
        bcopy(data+used, request, req_len);
        request[req_len] = '\0'; 
         
        int buLen = dlen + 1024;
	char httpBuf[buLen];
        int sendLen = 0;
        if(req_type == 'g')
	{
           sendLen = sprintf(httpBuf,"GET /%s HTTP/1.1\r\nHost:localhost\r\nConnection:Keep-Alive\r\nContent-Length:0\r\n\r\n", request);
           httpBuf[sendLen] = '\0';
        }
        else
	{
           used += req_len;
           unsigned plen = 0;
           if(used + uint_len > dlen)
                return -2;
           bcopy(data+used, &plen, uint_len);
           used += uint_len;
           if(used+plen > dlen)
                return -2;

          int iln= sprintf(httpBuf,"POST /%s HTTP/1.1\r\nHost:localhost\r\nConnection:Keep-Alive\r\nContent-type:application/x-www-form-urlencoded\r\nContent-length:%d\r\n\r\n", request, plen+4);
//   %s\r\n\r\n",req.c_str(), dlen, data);
          bcopy(data+used, &httpBuf[iln], plen);
          bcopy("\r\n\r\n", &httpBuf[iln+plen], 4);
          sendLen = iln + plen + 4;
        }

	m_iCounts++;
	int slen = Nantx_Write(m_socket, httpBuf, sendLen);
	//      int slen = send(m_socket, data, dlen, 0);
	DEBUG5("send length=", slen, m_sHostname,":", m_iPort);
	if(slen ==-1) {
		DEBUG5("send length=", slen, m_sHostname,":", m_iPort);
		disConnect();
		return -1;
	}
	if(!bReply){
		DEBUG1("needn't reply, so return");
		return 0;
	}

        int readlen = Nantx_Read( m_socket, wbuf, wsize, wbytes, 5);
        DEBUG4("wsize = ", wsize, "; readlen = ", readlen);
        if(readlen > 0)
        {
                DEBUG2("Yes, read length = ", readlen);
                wbytes = readlen;
                return 0;
        }
	disConnect();
	return -2;
}
/*
bool HttpConn::getStatus(int imax)
{
        if(m_iCounts >= imax)
             return false;

        if(m_bLive)
           return m_bLive;

        m_lCurtime = time(NULL);
        if(m_lLasttime < ( m_lCurtime - DEAD_CHECK_TIME))
        {
              disConnect();
              Connect();
              m_lLasttime = m_lCurtime;
        }
        return m_bLive;
}
*/
